package object

import (
	"fmt"
	"strings"

	"gitee.com/yanxingshuyuan/ming/ast"
)

type ObjectType string

const (
	NIL_OBJ   = "NIL"
	INT_OBJ   = "INT"
	BOOL_OBJ  = "BOOL"
	ERROR_OBJ = "ERROR"
	FN_OJB    = "FN"
)

type Object interface {
	Type() ObjectType
	Inspect() string
}

type Int struct {
	Value int
}

func (i *Int) Type() ObjectType { return INT_OBJ }
func (i *Int) Inspect() string  { return fmt.Sprintf("%d", i.Value) }

type Bool struct {
	Value bool
}

func (b *Bool) Type() ObjectType { return BOOL_OBJ }
func (b *Bool) Inspect() string  { return fmt.Sprintf("%t", b.Value) }

type Nil struct{}

func (n *Nil) Type() ObjectType { return NIL_OBJ }
func (n *Nil) Inspect() string  { return "nil" }

type Error struct {
	Message string
}

func (e *Error) Type() ObjectType { return ERROR_OBJ }
func (e *Error) Inspect() string  { return "ERROR: " + e.Message }

type Fn struct {
	Name   string
	Params []*ast.Param
	Body   *ast.BlockStmt
	Env    *Env
}

func (f *Fn) Type() ObjectType { return FN_OJB }
func (f *Fn) Inspect() string {
	var out strings.Builder

	params := []string{}
	for _, p := range f.Params {
		params = append(params, p.String())
	}

	out.WriteString("fn ")
	out.WriteString(f.Name)
	out.WriteString("(")
	out.WriteString(strings.Join(params, ", "))
	out.WriteString(") {\n")
	out.WriteString(f.Body.String())
	out.WriteString("\n}")

	return out.String()

}
